<template>
  <div ref="container" class="three-container"></div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

const container = ref(null);
let renderer = null;
let camera = null;
let scene = null;
let cube = null;
let animationFrameId = null;

// 初始化Three.js场景
const initScene = () => {
  // 场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xb1dbff);
  // AxesHelper：辅助观察的坐标系   坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴，对于three.js的3D坐标系默认y轴朝上
  const axesHelper = new THREE.AxesHelper(150);
  scene.add(axesHelper);
  const material = new THREE.MeshBasicMaterial({
    color: 0x0000ff, //设置材质颜色
    transparent: true, //开启透明
    opacity: 0.5, //设置透明度
  });

  // 相机  透视投影相机
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.set(0, 2, 5);
  camera.lookAt(scene.position); //指向mesh对应的位置

  // 渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(container.value.clientWidth, container.value.clientHeight);
  // .domElement本质上就是一个HTML元素  插入到任意HTML元素中
  container.value.appendChild(renderer.domElement);

  // 光源  环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  
  scene.add(ambientLight);

  //点光源：两个参数分别表示光源颜色和光照强度
  // 参数1：0xffffff是纯白光,表示光源颜色
  // 参数2：1.0,表示光照强度，可以根据需要调整
  const pointLight = new THREE.PointLight(0xffffff, 1.0);
  pointLight.intensity = 10.0; //光照强度
  pointLight.decay = 0.0; //设置光源不随距离衰减
  pointLight.position.set(0, 5, 0); //设置光源位置
  const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
  scene.add(pointLightHelper);
  scene.add(pointLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(5, 5, 5);
  scene.add(directionalLight);

  // ---------------- 立方体（MeshStandardMaterial 金属材质） ----------------
  // 1. 创建几何体（形状）
  // 参数：宽度(x轴), 高度(y轴), 深度(z轴)
  // 生成一个边长为1单位的标准立方体
  const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
  // 2. 创建材质（表面属性）
  // MeshPhongMaterial 特点：
  // - 需要光源才能显示高光
  // - 支持环境光、漫反射、镜面反射
  // - 性能优于 MeshStandardMaterial
  const cubeMaterial = new THREE.MeshStandardMaterial({
    color: 0x808080, // 金属基底色
    metalness: 0.9, // 金属度（0-1）
    roughness: 0.2, // 粗糙度（0-1）
  });
  // 3. 创建网格对象（组合几何体+材质）
  // 此时立方体默认位于场景原点(0,0,0)
  cube = new THREE.Mesh(cubeGeometry, material);
  cube.position.set(0, 0, 0);
  cube.castShadow = true; // 启用阴影投射
  // 4. 添加到场景
  scene.add(cube);

  // ---------------- 圆柱体（MeshLambertMaterial 漫反射材质） ----------------
  // 创建圆柱体几何体（参数：顶部半径, 底部半径, 高度, 径向分段数）
  const cylinderGeometry = new THREE.CylinderGeometry(0.5, 0.5, 2, 32);

  // 创建材质（使用与立方体相同的材质配置，但改为蓝色）
  const cylinderMaterial = new THREE.MeshLambertMaterial({
    color: 0x40e0d0, // 青绿色
    emissive: 0x004040, // 自发光颜色（暗青色）
    emissiveIntensity: 0.3, // 自发光强度
  });

  // 创建圆柱体网格对象
  const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial);

  // 设置圆柱体位置（沿X轴偏移2单位，避免与立方体重叠）
  cylinder.position.set(2, 0, 0);
  cylinder.castShadow = true;
  // 将圆柱体添加到场景
  scene.add(cylinder);

  // ---------------- 球体（MeshToonMaterial 卡通材质） ----------------
  const sphereGeometry = new THREE.SphereGeometry(0.75, 32, 32); // 半径0.75，32x32分段
  const sphereMaterial = new THREE.MeshToonMaterial({
    color: 0x7fff00, // 酸橙绿
  });
  const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
  sphere.position.set(-2, 0, 0); // 左上方位置
  sphere.castShadow = true;
  scene.add(sphere);

  // ---------------- 圆锥（MeshBasicMaterial 基础材质） ----------------
  const coneGeometry = new THREE.ConeGeometry(0.5, 2, 32); // 底面半径0.5，高度2
  const coneMaterial = new THREE.MeshBasicMaterial({
    color: 0xffa500, // 橙色
    wireframe: true, // 线框模式
    transparent: true, // 启用透明
    opacity: 0.8, // 透明度（0-1）
  });
  const cone = new THREE.Mesh(coneGeometry, coneMaterial);
  cone.position.set(0, 0, -2); // 场景后方位置
  scene.add(cone);

  // ---------------- 矩形平面（MeshPhysicalMaterial 物理材质） ----------------
  const planeGeometry = new THREE.PlaneGeometry(5, 5); // 5x5的矩形平面
  const planeMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x3d3d3d, // 深灰色
    clearcoat: 1.0, // 清漆层强度
    clearcoatRoughness: 0.1, // 清漆层粗糙度
    roughness: 0.5, // 基础粗糙度
    metalness: 0.05, // 微金属质感
  });
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -Math.PI / 2; // 旋转90度使其水平
  plane.position.y = -1; // 向下移动1单位作为地面
  plane.receiveShadow = true; // 启用阴影接收
  scene.add(plane);

  // ---------------- 圆平面 ----------------
  const circleGeometry = new THREE.CircleGeometry(1, 32); // 半径1，32分段
  const circleMaterial = new THREE.MeshNormalMaterial({
    flatShading: true, // 平面着色（显示几何分段）
  });
  const circle = new THREE.Mesh(circleGeometry, circleMaterial);
  circle.position.set(1.5, 0.1, -1.5); // 放置在矩形平面上方
  scene.add(circle);

  // 轨道控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;

  controls.addEventListener("change", function () {
    // 浏览器控制台查看相机位置变化
    console.log("camera.position", camera.position);
  });
};

// 动画循环
const animate = () => {
  animationFrameId = requestAnimationFrame(animate);

  // 立方体旋转
  //   cube.rotation.x += 0.01;
  //   cube.rotation.y += 0.01;
  // 生成一个Canvas画布(照片)，并把三维场景Scene呈现在canvas画布上面
  renderer.render(scene, camera);
};

// 窗口大小调整处理
const onWindowResize = () => {
  camera.aspect = container.value.clientWidth / container.value.clientHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(container.value.clientWidth, container.value.clientHeight);
};

onMounted(() => {
  initScene();
  animate();
  window.addEventListener("resize", onWindowResize);
});

onBeforeUnmount(() => {
  // 清理资源
  window.removeEventListener("resize", onWindowResize);
  cancelAnimationFrame(animationFrameId);
  container.value.removeChild(renderer.domElement);
  renderer.dispose();
});
</script>

<style scoped>
.three-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  padding: 0;
}

canvas {
  display: block;
}
.aa {
  color: #b1dbff;
}
</style>
